﻿using System;
using Microsoft.Xna.Framework;

namespace Serious
{
    public struct SwordAttackState
    {
        public Single roll;
        public Single blah;

        public SwordAttackState(Single roll, Single blah)
        {
            this.roll = roll;
            this.blah = blah;
        }

        public static SwordAttackState Interpolate(Func<Single, Single, Single, Single> interpolator, Single ratio, SwordAttackState low, SwordAttackState hi)
        {
            return new SwordAttackState(interpolator(low.roll, hi.roll, ratio), interpolator(low.blah, hi.blah, ratio));
        }
    }

    public struct SwordAttackFrame
    {
        public SwordAttackState state;
        public TimeSpan duration;

        public SwordAttackFrame(SwordAttackState state, TimeSpan duration)
        {
            this.state = state;
            this.duration = duration;
        }
    }

    public class SwordControllerAttack
    {
        public Sword subject;

        public SwordAttackState initial_state;
        public SwordAttackFrame[] frames;

        public TimeSpan current_relative_time;

        private SwordAttackState cached_prev_state;
        private TimeSpan cached_prev_time;
        private int cached_k;
        private SwordAttackFrame cached_next_frame;
        private TimeSpan cached_next_time;
        private bool cached_done;

        public SwordControllerAttack(Sword subject, SwordAttackState initial_state, SwordAttackFrame[] frames)
        {
            this.subject = subject;
            this.initial_state = initial_state;
            this.frames = frames;

            reset();
        }

        public void reset ()
        {
            current_relative_time = TimeSpan.Zero;

            cached_prev_state = initial_state;
            cached_prev_time = TimeSpan.Zero;
            cached_k = 0;
            cached_next_frame = frames[cached_k];
            cached_next_time = cached_prev_time + cached_next_frame.duration;

            cached_done = false;
        }

        private SwordAttackState determine_current_state ()
        {
            if (cached_done)
            {
                return frames[frames.Length - 1].state;
            }

            while (current_relative_time >= cached_next_time)
            {
                cached_prev_state = cached_next_frame.state;
                cached_prev_time = cached_next_time;
                cached_k++;
                if (cached_k >= frames.Length)
                {
                    cached_done = true;
                    return frames[frames.Length - 1].state;
                }
                cached_next_frame = frames[cached_k];
                cached_next_time += cached_next_frame.duration;
            }
            Single ratio = (Single)((current_relative_time - cached_prev_time).TotalSeconds / cached_next_frame.duration.TotalSeconds);
            return SwordAttackState.Interpolate(MathHelper.SmoothStep, ratio, cached_prev_state, cached_next_frame.state);
        }

        public void Update (GameTime gameTime)
        {
            current_relative_time += gameTime.ElapsedGameTime;
            SwordAttackState current_state = determine_current_state();
            subject.roll = current_state.roll;
            subject.blah = current_state.blah;
        }
    }
}
